package httproxy

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/sirupsen/logrus"
	"http_proxy_v2/internal/healthchecker"
	"http_proxy_v2/pkg/utils"
	"io/ioutil"
	"net/http"
	"os"
	"time"
)

var (
	ProxyConfPath  = "configs/proxy.json"
	ProxyServerMap = make(map[int]*http.Server)
)

func loadProxyConfig() (proxy Proxy, err error) {
	if ok, _ := utils.PathExists(ProxyConfPath); !ok { // 如果配置文件不存在
		return
	}
	open, err := os.Open(ProxyConfPath)
	if err != nil {
		err = errors.New(("open the proxy.json fail"))
		return
	}
	all, err := ioutil.ReadAll(open)
	if err != nil {
		err = errors.New(("read proxy.json is fail"))
		return
	}

	err = json.Unmarshal(all, &proxy)
	return
}

// signChan 信号通道 0 ok 1 异常
func LoadProxyServer(signChan chan<- error) {
	if proxyConf, err := loadProxyConfig(); err != nil {
		logrus.Error("获取配置出错:", err)
		signChan <- err
	} else if proxyConf.Port == 0 { // 未找到配置文件
		signChan <- nil
	} else {
		// 如果有静态文件目录需要对外访问
		if proxyConf.StaticInfo.Root != "" {
			http.Handle(proxyConf.StaticInfo.Root, http.StripPrefix(proxyConf.StaticInfo.Root, http.FileServer(http.Dir(proxyConf.StaticInfo.Path))))
		}
		// 代理转发接口
		proxy := NewProxy(proxyConf)
		healthchecker.Run()
		healthchecker.H.Reset(proxy)
		go handleHresult()
		http.HandleFunc("/", proxy.ServeRequest)

		addr := fmt.Sprintf("%s:%d", "", proxyConf.Port)

		server := &http.Server{
			Addr:           addr,
			ReadTimeout:    30 * time.Second,
			WriteTimeout:   30 * time.Second,
			MaxHeaderBytes: 2 << 16,
		}

		logrus.Info(fmt.Sprintf("[info] start http server listening %s", server.Addr))
		time.AfterFunc(2*time.Second, func() {
			ProxyServerMap[proxyConf.Port] = server
			signChan <- nil // 2秒后，发送服务启动成功通知
		})
		go func() {
			err = server.ListenAndServe()
			if err != nil {
				logrus.Error("start server失败", err)
				signChan <- err
			}
		}()
	}
}

func Shutdown(port int, ctx context.Context) (err error) {
	if server, ok := ProxyServerMap[port]; ok {
		err = server.Shutdown(ctx)
	}
	return
}

//监听健康检查返回的消息
/*type BackChan struct {
	Type     int         //0 死亡 1复活
	UpStream interface{} //上游服务器信息
}*/
var msg healthchecker.BackChan

func handleHresult() {
	for {
		select {
		case msg := <-healthchecker.H.Hresult:
			fmt.Println(msg.Type, msg.UpStream.(UpClient).Addr)
		}
	}
}
